import asyncio
import importlib
import inspect
import logging
import os
import os.path as osp
import sys
import time
from functools import partial
from logging.handlers import RotatingFileHandler
from typing import Any, Dict, Generator, Iterable, List, Optional, Union


def load_class_from_string(class_path: str, path=None):
    """
    从字符串路径动态加载类
    
    参数:
        class_path (str): 类的完整路径，如'package.module.ClassName'
        path (str): 可选的搜索路径
        
    返回:
        加载的类对象
    """
    path_in_sys = False
    if path:
        if path not in sys.path:
            path_in_sys = True
            sys.path.insert(0, path)  # 临时添加搜索路径

    try:
        # 解析并导入模块和类
        module_name, class_name = class_path.rsplit('.', 1)
        module = importlib.import_module(module_name)
        cls = getattr(module, class_name)
        return cls
    finally:
        # 清理临时添加的搜索路径
        if path and path_in_sys:
            sys.path.remove(path)


def create_object(config: Union[Dict, Any] = None):
    """
    根据配置字典动态创建对象实例
    
    该函数实现了一个工厂模式，可以根据配置动态创建对象。它支持两种主要的创建方式：
    1. 通过类直接实例化
    2. 通过可调用对象（函数）创建
    
    @param {Union[Dict, Any]} config - 配置字典，必须包含'type'键，用于指定要创建的对象类型
    - 如果config不是字典，则直接返回原值
    
    @returns {Any} 返回创建的对象实例或原始输入
    """
    if config is None or not isinstance(config, dict):
        return config
    assert isinstance(config, dict) and 'type' in config

    config = config.copy()  # 创建配置的副本以避免修改原始数据
    obj_type = config.pop('type')  # 提取并移除type键，剩余的键值对作为参数
    
    if isinstance(obj_type, str):
        # 如果类型是字符串，则动态加载对应的类
        obj_type = load_class_from_string(obj_type)
        
    if inspect.isclass(obj_type):
        # 如果是类，直接实例化
        obj = obj_type(**config)
    else:
        # 如果是可调用对象，使用partial创建部分应用的函数
        assert callable(obj_type)
        obj = partial(obj_type, **config)
    return obj


async def async_as_completed(futures: Iterable[asyncio.Future]):
    """
    asyncio.as_completed的异步包装器
    
    参数:
        futures: Future对象的迭代器
        
    返回:
        异步生成器，产生已完成的Future结果
    """
    loop = asyncio.get_event_loop()
    wrappers = []
    # 为每个Future创建包装器
    for fut in futures:
        assert isinstance(fut, asyncio.Future)
        wrapper = loop.create_future()
        fut.add_done_callback(wrapper.set_result)
        wrappers.append(wrapper)
    # 按完成顺序yield结果
    for next_completed in asyncio.as_completed(wrappers):
        yield await next_completed


def filter_suffix(response: Union[str, List[str]], suffixes: Optional[List[str]] = None) -> str:
    """
    使用后缀过滤响应文本
    
    参数:
        response: LLM生成的响应文本或文本列表
        suffixes: 需要删除的后缀列表
        
    返回:
        清理后的响应文本
    """
    if suffixes is None:
        return response
        
    # 处理单个字符串输入
    batched = True
    if isinstance(response, str):
        response = [response]
        batched = False
        
    # 过滤每个响应中的后缀
    processed = []
    for resp in response:
        for item in suffixes:
            if item in resp:
                resp = resp.split(item)[0]
        processed.append(resp)
        
    # 返回适当的格式
    if not batched:
        return processed[0]
    return processed


def get_logger(
    name: str = 'lagent',
    level: str = 'debug',
    fmt: str = '%(asctime)s %(levelname)8s %(filename)20s %(lineno)4s - %(message)s',
    add_file_handler: bool = False,
    log_dir: str = 'log',
    log_file: str = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime()) + '.log',
    max_bytes: int = 50 * 1024 * 1024,  # 50MB
    backup_count: int = 3,
):
    """
    配置并获取日志记录器
    
    参数:
        name: 日志记录器名称
        level: 日志级别
        fmt: 日志格式
        add_file_handler: 是否添加文件处理器
        log_dir: 日志目录
        log_file: 日志文件名
        max_bytes: 单个日志文件的最大大小
        backup_count: 保留的备份文件数量
        
    返回:
        配置好的日志记录器
    """
    logger = logging.getLogger(name)
    logger.propagate = False  # 避免日志传播
    logger.setLevel(getattr(logging, level.upper(), logging.DEBUG))

    # 配置控制台处理器
    formatter = logging.Formatter(fmt)
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)

    # 配置文件处理器（如果需要）
    if add_file_handler:
        if not osp.exists(log_dir):
            os.makedirs(log_dir)
        log_file_path = osp.join(log_dir, log_file)
        file_handler = RotatingFileHandler(
            log_file_path, 
            maxBytes=max_bytes, 
            backupCount=backup_count, 
            encoding='utf-8'
        )
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)

    return logger


class GeneratorWithReturn:
    """
    带返回值的生成器包装类
    
    用于捕获生成器的返回值
    
    属性:
        generator: 原始生成器
        ret: 生成器的返回值
    """

    def __init__(self, generator: Generator):
        self.generator = generator
        self.ret = None

    def __iter__(self):
        """
        迭代生成器并保存返回值
        """
        self.ret = yield from self.generator
        return self.ret
